// 参考： https://threejsfundamentals.org/threejs/lessons/threejs-post-processing.html
import { 
  AmbientLight,
  BoxGeometry,
  CubeTextureLoader,
  Mesh,
  MeshPhongMaterial,
  MeshStandardMaterial,
  PerspectiveCamera,
  PlaneGeometry,
  RepeatWrapping,
  Scene, 
  SphereGeometry, 
  SpotLight, 
  TextureLoader, 
  Vector3, 
  WebGLRenderer,
} from "three";
import stats from '../utils/stats';
// 调用
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
import { BokehPass } from 'three/examples/jsm/postprocessing/BokehPass';
import { GUI } from "dat.gui";

let renderer = setRenderer();
let camera = setCamera();
let scene = new Scene();
initDefaultLighting(scene);
let groundPlane = addLargeGroundPlane(scene, true);
groundPlane.position.y = -8;

let txetureLoader = new TextureLoader();
let urls = [
  '/textures/cubemap/flowers/right.png',
  '/textures/cubemap/flowers/left.png',
  '/textures/cubemap/flowers/top.png',
  '/textures/cubemap/flowers/bottom.png',
  '/textures/cubemap/flowers/front.png',
  '/textures/cubemap/flowers/back.png',
];
let cubeLoader = new CubeTextureLoader();

let sphereMaterial = new MeshStandardMaterial({
  envMap: cubeLoader.load(urls),
  normalMap: txetureLoader.load('/textures/engraved/Engraved_Metal_003_NORM.jpg'),
  aoMap: txetureLoader.load('/textures/engraved/Engraved_Metal_003_OCC.jpg'),
  color: 0xffffff,
  metalness: 1,
  roughness: 0.3
});
let sphereGeom = new SphereGeometry(5, 50, 50);
let sphere = new Mesh(sphereGeom, sphereMaterial);
sphere.castShadow = true;
sphere.position.x = 0;
scene.add(sphere);

let boxMaterial_1 = new MeshStandardMaterial({color: 0x0066ff});
let m1 = new BoxGeometry(10, 10, 10);
let m1m = new Mesh(m1, boxMaterial_1);
m1m.position.set(-35, 1, -40);
scene.add(m1m);

// 生成后排矩形
let totalWidth = 220;
let nBoxes = 10;
for (let i = 0; i < nBoxes; i++) {
  let box = new BoxGeometry(10, 10, 10);
  let mat = new MeshStandardMaterial({color: 0x66ff00});
  let mesh = new Mesh(box, mat);
  let x = -(totalWidth / 2) + (totalWidth / nBoxes) * i;
  mesh.position.set(x, i, -120);

  scene.add(mesh);
}

let params = {
  focus: 10,
  aspect: camera.aspect,
  aperture: 0.0002,
  maxblur: 1,
};
let renderPass = new RenderPass(scene, camera);
let bokehPass = new BokehPass(scene, camera, params);
bokehPass.renderToScreen = true;

let composer = new EffectComposer(renderer);
composer.addPass(renderPass);
composer.addPass(bokehPass);

const trackballControls = new OrbitControls(camera, renderer.domElement);

let gui = new GUI();
let controls = {
  focus: 1,
  aperture: 0.0002,
  maxblur: 1,
};
let folder = gui.addFolder('Bokeh');
folder.open();
folder.add(controls, 'focus', 0, 200, 0.01).onChange(val => {
  console.log(bokehPass);
  (<any>bokehPass.uniforms).focus.value = val
});
folder.add(controls, 'aperture', 0, 0.0005, 0.000001).onChange(val => {
  (<any>bokehPass.uniforms).aperture.value = val;
});
folder.add(controls, 'maxblur', 0, 1, 0.1).onChange(val => {
  (<any>bokehPass.uniforms).maxblur.value = val;
});

render();
function render() {
  stats.update();
  trackballControls.update();

  requestAnimationFrame(render);
  composer.render();
}


function setRenderer() {
  const renderer = new WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 支持阴影生成 
  renderer.shadowMap.enabled = true;
  document.body.appendChild(renderer.domElement);

  return renderer
}

function setCamera(): PerspectiveCamera {
  let camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
  camera.position.set(0, 20, 40);

  return camera;
}

function initDefaultLighting(scene: any, initialPosition?: any) {
  let position = (initialPosition !== undefined) ? initialPosition : new Vector3(-10, 30, 40);
  
  let spotLight = new SpotLight(0xffffff);
  spotLight.position.copy(position);
  spotLight.shadow.mapSize.width = 2048;
  spotLight.shadow.mapSize.height = 2048;
  spotLight.shadow.camera.fov = 15;
  spotLight.castShadow = true;
  spotLight.decay = 2;
  spotLight.penumbra = 0.05;
  spotLight.name = "spotLight"

  let ambientLight = new AmbientLight(0x343434);
  ambientLight.name = "ambientLight";
  
  scene.add(spotLight);
  scene.add(ambientLight);  
}


/**
 * Add a simple ground plance to the provided scene
 * 
 * @param {THREE.Scene} scene 
 */
function addLargeGroundPlane(scene: Scene, useTexture: boolean = false) {
  // create the ground plane
  let planeGeometry = new PlaneGeometry(10000, 10000);
  let planeMaterial = new MeshPhongMaterial({
      color: 0xffffff
  });

  if (useTexture) {
    let textureLoader = new TextureLoader();
    planeMaterial.map = textureLoader.load("/textures/general/floor-wood.jpg");
    planeMaterial.map.wrapS = RepeatWrapping; 
    planeMaterial.map.wrapT = RepeatWrapping; 
    planeMaterial.map.repeat.set(80,80)
  }
  let plane = new Mesh(planeGeometry, planeMaterial);
  plane.receiveShadow = true;

  // rotate and position the plane
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.set(0, 0, 0);

  scene.add(plane);

  return plane;
}
